package dcedit.util;

// Import Java SDK Classes
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.swing.*;

/** TemplateToken class */
public class TemplateToken implements Comparable<TemplateToken> {
   /** Token (with delimiters) field */
   private String tokenWithDelimiters;

   /** Token (without delimiters) field */
   private String tokenWithoutDelimiters;

   /** Component (value) field */
   private JComponent displayComponent;

   /** Constructor */
   public TemplateToken(final String TOKEN) {
      this(TOKEN,
           Constants.BEGIN_TEMPLATE_EXPRESSION_FIELD.getText(),
           Constants.END_TEMPLATE_EXPRESSION_FIELD.getText());
   } // END constructor

   /** Constructor */
   public TemplateToken(final String TOKEN,
                        final String BEGIN_TEMPLATE_EXPRESSION,
                        final String END_TEMPLATE_EXPRESSION) {
      tokenWithDelimiters = new String(TOKEN);
      tokenWithoutDelimiters = tokenWithDelimiters.replace(BEGIN_TEMPLATE_EXPRESSION,"")
                                                  .replace(END_TEMPLATE_EXPRESSION,"");
      displayComponent = createDisplayComponent();
   } // END constructor

   /**
    * getTokenWithDelimiters
    * @return String tokenWithDelimiters
    */
   public String getTokenWithDelimiters() {
      return tokenWithDelimiters;
   } // END getTokenWithDelimiters

   /**
    * getTokenWithoutDelimiters
    * @return String tokenWithoutDelimiters
    */
   public String getTokenWithoutDelimiters() {
      return tokenWithoutDelimiters;
   } // END getTokenWithoutDelimiters

   /**
    * getDisplayComponent
    * @return JComponent the component
    */
   public JComponent getDisplayComponent() {
      return displayComponent;
   } // END getDisplayComponent

   /**
    * hasTag method
    * @return true or false if tokenWithoutDelimiters has a tag
    * (E.g.: tagName:tagValue;  E.g.: tagName:tagValue1|tagValue2|tagValue3.)
    */
   public boolean hasTag() {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.matches("(?i).*:.*");
      } else {
         return false;
      } // END if/else
   } // END hasTag

   /**
    * getTagMethod
    * @return The tag to return from tokenWithoutDelimiters
    */
   public String getTag() {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.replaceAll("(?i):.*","");
      } else {
         return "";
      } // END if/else
   } // END getTag

   /**
    * hasOptions method
    * @return true or false if tokenWithoutDelimiters has multiple options
    * (E.g.: tagValue1|tagValue2|tagValue3;  E.g.: tagName:tagValue1|tagValue2|tagValue3.)
    */
   public boolean hasOptions() {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.contains(Constants.PIPE_CHAR);
      } else {
         return false;
      } // END if/else
   } // END hasOptions

   public String[] getOptions() {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.replaceFirst("^.*:", "").split(Constants.PIPE_EXP);
      } else {
         return new String[0];
      } // END if/else
   } // END getOptions

   /**
    * hasDateTimeText method
    * @return true or false if tokenWithoutDelimiters contains the words date and time.
    * @see #hasDateText()
    * @see #hasTimeText()
    */
   public boolean hasDateTimeText() {
      return hasDateText() && hasTimeText();
   } // END hasDateTimeText

   /**
    * hasDateText method
    * @return true or false if tokenWithoutDelimiters contains the word date.
    * @see #hasText(String)
    */
   public boolean hasDateText() {
      return hasText("date");
   } // END hasDateText

   /**
    * hasTimeText method
    * @return true or false if tokenWithoutDelimiters contains the word time.
    * @see #hasText(String)
    */
   public boolean hasTimeText() {
      return hasText("time");
   } // END hasTimeText

   /**
    * hasText method
    * @param TEXT The supplied text string.  Can't be null.
    * @return true or false if tokenWithoutDelimiters contains the supplied TEXT string.
    */
   public boolean hasText(final String TEXT) {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.toLowerCase().contains(TEXT.toLowerCase());
      } else {
         return false;
      } // END if/else
   } // END hasText

   /**
    * matchesExpression method
    * @param TEXT The supplied text string.  Can't be null.
    * @return true or false if tokenWithoutDelimiters matches the regular expression defined in the TEXT string.
    */
   public boolean matchesExpression(final String TEXT) {
      if(null != tokenWithoutDelimiters) {
         return tokenWithoutDelimiters.matches("(?i)(.*:)?\\d*d\\d+");
      } else {
         return false;
      } // END if/else
   } // END matchesExpression

   /**
    * getDisplayLabel method
    * @return The string text to display as this token's label.
    */
   public String getDisplayLabel() {
      return (hasTag() ? getTag() : getTokenWithoutDelimiters());
   } // END getDisplayLabel

   /**
    * getDisplayComponent method
    * @return The component to display as token's selection field.
    */
   public JComponent createDisplayComponent() {
      // Get the current date object.
      final Date NOW = Calendar.getInstance().getTime();

      // Instead of creating a text field, create a combo box.
      if(hasOptions()) {
         return new TemplateTokenComboBox(getOptions());
      } else if(hasDateTimeText()) {
         // Default to current date and time stamp.
         SimpleDateFormat FMT = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss");
         return new TemplateTokenTextField(FMT.format(NOW));
      } else if(hasDateText()) {
         // Default to current date stamp.
         SimpleDateFormat FMT = new SimpleDateFormat("MM/dd/yyyy");
         return new TemplateTokenTextField(FMT.format(NOW));
      } else if(hasTimeText()) {
         // Default to current time stamp.
         SimpleDateFormat FMT = new SimpleDateFormat("hh:mm:ss");
         return new TemplateTokenTextField(FMT.format(NOW));
      } else if(hasText("year") || hasText("yyyy")) {
         // Default to current 4-digit year stamp.
         SimpleDateFormat FMT = new SimpleDateFormat("yyyy");
         return new TemplateTokenTextField(FMT.format(NOW));
      } else if(hasText("yy")) {
         // Default to current 2-digit year stamp.
         SimpleDateFormat FMT = new SimpleDateFormat("yy");
         return new TemplateTokenTextField(FMT.format(NOW));
      } else if(hasText("uniqueNumber")) {
         // Default to current time milliseconds.
         return new TemplateTokenTextField(String.valueOf(System.currentTimeMillis()));
      } else if(hasText("author") || hasText("user")) {
         // Default to the user's name.
         return new TemplateTokenTextField(System.getProperty(Constants.USER_NAME_PROPERTY));
      // Roll dice tokens
      // d# | #d# | tag:d# | tag:#d#
      } else if(matchesExpression("(?i)(.*:)?\\d*d\\d+")) {
         final String DICE_EXPR = getTokenWithoutDelimiters().replaceFirst("^.*:", "");

         // Default to a simple dice roll.
         try {
            final String[] DICE_TOKENS = DICE_EXPR.split("(?i)d");

            int numDice = 1;  // default to 1 die.
            int numSides = 2; // default to 2 sides.
            int total = 0;    // total begins at zero.

            if(DICE_TOKENS.length == 2) {
               if(!DICE_TOKENS[0].isEmpty()) numDice = Integer.parseInt(DICE_TOKENS[0]);
               if(!DICE_TOKENS[1].isEmpty()) numSides = Integer.parseInt(DICE_TOKENS[1]);
            } else {
               System.out.println("Malformed dice expression: " + DICE_EXPR);
            } // END if/else

            // For each dice roll
            while(numDice > 0) {
               total += Util.getRandomInt(numSides);
               --numDice;
            } // END loop

            return new TemplateTokenTextField(String.valueOf(total));
         } catch(Exception e) {
            System.out.println(e.getMessage());
            return new TemplateTokenTextField();
         } // END try/catch
      } else {
         return new TemplateTokenTextField();
      } // END if/else
   } // END getDisplayComponent

   /** compareTo method */
   public int compareTo(TemplateToken templateToken) {
      return this.getTokenWithoutDelimiters().compareTo(templateToken.getTokenWithoutDelimiters());
   } // END compareTo

   /** Inner class TemplateTokenComboBox */
   public class TemplateTokenComboBox extends JComboBox<String> {
      public static final long serialVersionUID = 1300401490811L;
      public TemplateTokenComboBox(String[] options) { super(options); }
      public String toString() { return ""; }
   } // END inner class TemplateTokenComboBox

   /** Inner class TemplateTokenTextField */
   public class TemplateTokenTextField extends JTextField {
      public static final long serialVersionUID = 1300401491330L;
      public String initialText = "";
      public TemplateTokenTextField() { this(""); }
      public TemplateTokenTextField(String text) { initialText = new String(text); setText(text); }
      public String toString() { return initialText; }
   } // END inner class TemplateTokenTextField
} // END class TemplateToken